import java.util.function.Function;

import javax.management.RuntimeErrorException;

public class Result<T, E> {
    private T ok;
    private E err;

    private Result(T ok, E err) {
        this.ok = ok;
        this.err = err;
    }

    public static <T, E> Result<T, E> Ok(T t) {
        return new Result<T,E>(t, null);
    }

    public static <T, E> Result<T, E> Err(E e) {
        return new Result<T,E>(null, e);
    }

    public T unwrap() {
        if(this.err != null) {
            throw new RuntimeErrorException(new Error(this.err.toString()));
        }

        return this.ok;
    }

    public <U> Result<U, E> map(Function<T, U> f) {
        if(this.err != null) {
            return Result.Err(this.err);
        }

        return Result.Ok(f.apply(this.ok));
    }

    public <U> Result<T, U> mapErr(Function<E, U> f) {
        if(this.err != null) {
            return Result.Err(f.apply(this.err));
        }

        return Result.Ok(this.ok);
    }

        public <U> Result<U, E> andThen(Function<T, Result<U, E>> f) {
        if(this.err != null) {
            return Result.Err(this.err);
        }

        return f.apply(this.ok);
    }
    
    @Override
    public String toString() {
        if(this.err == null) {
            return this.ok.toString();
        }
        return this.err.toString();
    }

}



